package models

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/cy77cc/hioshop/global"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
	"math/rand"
	"time"
)

type Address struct {
	Model
	Name       string `gorm:"type:varchar(50);default:''" json:"name"`
	UserId     uint   `json:"user_id" gorm:"type:mediumint;default:0"`
	CountryId  int16  `json:"country_id" gorm:"type:smallint;default:0"`
	ProvinceId int16  `json:"province_id" gorm:"type:smallint;default:0"`
	CityId     int16  `json:"city_id" gorm:"type:smallint;default:0"`
	DistrictId int16  `json:"district_id" gorm:"type:smallint;default:0"`
	Address    string `json:"address" gorm:"type:varchar(120);default:''"`
	Mobile     string `json:"mobile" gorm:"type:varchar(60);default:''"`
	IsDefault  uint8  `json:"is_default" gorm:"type:tinyint unsigned;default:0"`
	IsDelete   int8   `json:"is_delete" gorm:"type:tinyint;default:0"`
}

func (a *Address) GetAddressList() (list []Address, err error) {
	ctx := context.Background()
	// 用address id作为分数
	key := fmt.Sprintf("user:%d.address", a.UserId)
	zRange := global.REDIS.ZRange(ctx, key, 0, -1)
	if len(zRange.Val()) == 0 {
		err = global.DB.Model(&a).Where("is_delete=0").Find(&list).Error
		if len(list) == 0 {
			global.REDIS.ZAdd(ctx, key, redis.Z{Score: float64(0), Member: ""})
		}
		for _, v := range list {
			data, _ := json.Marshal(v)
			global.REDIS.ZAdd(ctx, key, redis.Z{Score: float64(v.ID), Member: data})
		}

		global.REDIS.Expire(ctx, key, time.Hour+time.Second*time.Duration(rand.Intn(60)))
		return
	}

	for _, v := range zRange.Val() {
		var data Address
		err = json.Unmarshal([]byte(v), &data)
		if err != nil {
			return
		}
		list = append(list, data)
	}

	return
}

func (a *Address) Create() (err error) {
	if a.ID > 0 {
		err = global.DB.Model(&Address{}).Where(map[string]any{
			"id": a.ID,
		}).Updates(map[string]any{
			"name":        a.Name,
			"mobile":      a.Mobile,
			"province_id": a.ProvinceId,
			"city_id":     a.CityId,
			"district_id": a.DistrictId,
			"address":     a.Address,
			"is_default":  a.IsDefault,
		}).Error
	} else {
		err = global.DB.Model(&Address{}).Create(a).Error
	}
	ctx := context.Background()
	key := fmt.Sprintf("user:%d.address", a.UserId)
	data, _ := json.Marshal(a)
	global.REDIS.ZAdd(ctx, key, redis.Z{Score: float64(a.ID), Member: data})
	global.REDIS.Expire(ctx, key, time.Hour+time.Second*time.Duration(rand.Intn(60)))
	return err
}

func (a *Address) Query() (err error) {
	ctx := context.Background()
	// 用address id作为分数
	key := fmt.Sprintf("user:%d.address", a.UserId)
	queryId := fmt.Sprintf("%d", a.ID)
	res := global.REDIS.ZRangeByScore(ctx, key, &redis.ZRangeBy{Min: queryId, Max: queryId})
	if len(res.Val()) == 0 {
		err = global.DB.Model(&Address{}).Where(a).Where("is_delete=0").Find(a).Error
		if errors.Is(err, gorm.ErrRecordNotFound) {
			global.REDIS.ZAdd(ctx, key, redis.Z{Score: float64(a.ID), Member: ""})
			return
		} else {
			data, _ := json.Marshal(a)
			global.REDIS.ZAdd(ctx, key, redis.Z{Score: float64(a.ID), Member: data})
			return
		}
	}

	err = json.Unmarshal([]byte(res.Val()[0]), a)

	return
}

func (a *Address) Delete() (err error) {
	ctx := context.Background()
	// 用address id作为分数
	key := fmt.Sprintf("user:%d.address", a.UserId)
	queryId := fmt.Sprintf("%d", a.ID)
	global.REDIS.ZRemRangeByScore(ctx, key, queryId, queryId)

	err = global.DB.Model(&Address{}).Where(a).Delete(a).Error
	return
}
